#ifndef _NE_FONT_H_
#define _NE_FONT_H_

#include <common/Unicode.h>
#include <mathematics/Vector4.h>
#include <graphics/Texture.h>
#include <graphics/DynamicGeometry.h>

namespace ne
{
 /**
 *
 * A structure that describe a glyph.
 *
 *
 * Glyph metrics:
 * --------------
 * Horizontal:
 *              ^        xmin                     xmax
 *              |         |                         |
 *              |         |<-------- width -------->|
 *              |         |                         |    
 *              |         +-------------------------+----------------- ymax
 *              |         |    ggggggggg   ggggg    |     ^        ^
 *              |         |   g:::::::::ggg::::g    |     |        | 
 *              |         |  g:::::::::::::::::g    |     |        | 
 *              |         | g::::::ggggg::::::gg    |     |        | 
 *              |         | g:::::g     g:::::g     |     |        | 
 * h_bearing_x -|-------->| g:::::g     g:::::g     | h_bearing_y  | 
 *              |         | g:::::g     g:::::g     |     |        | 
 *              |         | g::::::g    g:::::g     |     |        | 
 *              |         | g:::::::ggggg:::::g     |     |        |  
 *              |         |  g::::::::::::::::g     |     |      height
 *              |         |   gg::::::::::::::g     |     |        | 
 *  baseline ---*---------+---- gggggggg::::::g-----*--------->    |
 *            / |         |             g:::::g     |              | 
 *     origin   |         | gggggg      g:::::g     |              | 
 *              |         | g:::::gg   gg:::::g     |              | 
 *              |         |  g::::::ggg:::::::g     |              | 
 *              |         |   gg:::::::::::::g      |              | 
 *              |         |     ggg::::::ggg        |              | 
 *              |         |         gggggg          |              v
 *              |         +-------------------------+----------------- ymin
 *              |                                   |
 *              |------------- h_advance ---------->|
 *
 *
 *
 * Vertical:
 *                                 baseline
 *                                    |
 *                       xmin         |           xmax
 *                        |           |             |
 *            v_bearing_x |<----------|  origin     |
 *                        |           | /           |    
 *           -------------+-----------*-------------+----------------->
 *                        |           |             |     |        |
 *                        |           |             | v_bearing_y  |
 *                        |           |             |     v        |
 *                 ymax --+-----------+-------------+--------      |
 *                        |    ggggggggg   ggggg    |    ^         |
 *                        |   g:::::::::ggg::::g    |    |         |
 *                        |  g:::::::::::::::::g    |    |         |
 *                        | g::::::ggggg::::::gg    |    |         |
 *                        | g:::::g     g:::::g     |    |         |
 *                        | g:::::g     g:::::g     |    |         |
 *                        | g:::::g     g:::::g     |    |     v_advance
 *                        | g::::::g    g:::::g     |    |         |
 *                        | g:::::::ggggg:::::g     |    |         | 
 *                        |  g::::::::::::::::g     |  height      |
 *                        |   gg::::::::::::::g     |    |         |
 *                        |     gggggggg::::::g     |    |         |
 *                        |             g:::::g     |    |         |
 *                        | gggggg      g:::::g     |    |         |
 *                        | g:::::gg   gg:::::g     |    |         |
 *                        |  g::::::ggg:::::::g     |    |         |
 *                        |   gg:::::::::::::g      |    |         |
 *                        |     ggg::::::ggg        |    |         |
 *                        |         gggggg          |    v         |
 *                 ymin --+-----------+-------------+-------       |
 *                        |           |             |              v
 *           -------------+-----------*-------------+-----------------
 *                        |           |             |
 *                        |           v             |
 *                        |                         |
 *                        |<-------- width -------->|
 */

    enum FontType
    {
        FT_TRUETYPE = 0,
        FT_IMAGE = 1
    };

    enum FontHintType
    {
        FHT_NORMAL = 0,
        FHT_LIGHT = 1,
        FHT_MONO = 2,
        FHT_LCD = 3,
        FHT_LCD_V = 4,
    };

    enum FontStyleType
    {
        FST_NORMAL = 0x00,
        FST_BACKGROUND = 0x01,
        FST_BOLD = 0x02,
        FST_ITALIC = 0x04,
        FST_OUTLINE = 0x08,
        FST_UNDERLINE = 0x10,
        FST_OVERLINE = 0x20,
    };

    enum FontLayout
    {
        FL_LEFT_TO_RIGHT = 0,
        FL_RIGHT_TO_LEFT = 1,
        FL_TOP_TO_BOTTOM = 2,
        FL_BOTTOM_TO_TOP = 3,
        FL_HORIZONTAL = 4,
        FL_VERTICAL = 5,
    };

    struct FontStyle
    {
        uint32_t mask;
        Color foreColor;
        Color backColor;
        Color outlineColor;
        Color underlineColor;
        Color overlineColor;
        int kerning;
        int lineGap;
    };

    struct Glyph
    {
        utf32_t code;
        real width;
        real height;
        real horiBearingX;
        real horiBearingY;
        real horiAdvance;
        real vertBearingX;
        real vertBearingY;
        real vertAdvance;
        Vector2 texCoords[2];
    };

    typedef std::map<utf32_t, Glyph*> GlyphMap;
    typedef GlyphMap::iterator GlyphMapIterator;
    typedef GlyphMap::const_iterator GlyphMapConstIterator;

    class NEAPI Font : public Resource
    {
        public:
            struct FontVertex
            {
                Vector3 pos;
                Vector2 tex;
                Color col;
            };

            typedef std::list<FontVertex*> FontVertexList;

        public:
            Font(ResourceManager *pManager,
                 const uint64_t id,
                 const std::string &name,
                 const std::string &fileName,
                 const bool isManual,
                 ManualResourceLoader *pLoader);

            void createInternalFont(const TexturePtr &pTexture,
                                    const FontType ft, const uint32_t fontSize,
                                    const uint32_t width, const uint32_t height,
                                    const FontHintType hint);

            void freeInternalFont();

            Glyph* createGlyph(const utf32_t c);

            Glyph* getGlyph(const utf32_t c) const;

            bool destroyGlyph(const utf32_t c);

            void destroyAllGlyphs();

            size_t getGlyphNum() const;

            FontType getFontType() const;

            FontHintType getFontHintType() const;

            uint32_t getFontSize() const;

            uint32_t getFontWidth() const;

            uint32_t getFontHeight() const;

            bool isFixedWidth() const;

            const std::string& getFamilyName() const;

            const std::string& getStyleName() const;

            const TexturePtr& getTexture() const;

            void renderText2D(const std::string &text, const Vector3 &v,
                              const real width, const real height,
                              const Color &color=Color::WHITE,
                              const real textSpace=-2.0f);

            void renderText2D(const Unicode &text, const Vector3 &v,
                              const real width, const real height,
                              const Color &color=Color::WHITE,
                              const real textSpace=-2.0f);

            real getDefaultGlyphOffset(const FontLayout layout=FL_LEFT_TO_RIGHT) const;
            real getGlyphOffset(const utf32_t c, const FontLayout layout=FL_LEFT_TO_RIGHT) const;

            bool genGlyphGeometry(const utf32_t c, const DynamicGeometryPtr &pGeometry,
                                  const Vector3 &pos, const Vector3 &xAxis, const Vector3 &yAxis,
                                  const Color &color=Color::WHITE, const FontLayout layout=FL_LEFT_TO_RIGHT);

            void updateFont();

            virtual ~Font();

        protected:
            virtual bool loadImplement();

            virtual bool unloadImplement();

            virtual size_t _calculateSize() const;

        private:
            FontType mFontType;
            FontHintType mFontHintType;
            uint32_t mFontSize;
            uint32_t mWidth;
            uint32_t mHeight;

            bool mIsFixedWidth;

            bool mInternalTextureCreated;
            TexturePtr mpTexture;
            GlyphMap mGlyphMap;

            std::string mFamilyName;
            std::string mStyleName;
    };

    class NEAPI FontPtr : public SharedPtr<Font>
    {
        public:
            FontPtr() : SharedPtr<Font>() {}
            explicit FontPtr(Font *pFont) : SharedPtr<Font>(pFont) {}
            FontPtr(const FontPtr &pFont) : SharedPtr<Font>(pFont) {}

            FontPtr(const ResourcePtr &p)
                : SharedPtr<Font>()
            {
                mpPtr = static_cast<Font*>(p.ptr());
                mpUseCount = p.getUseCountPtr();
                if (mpUseCount)
                {
                    ++(*mpUseCount);
                }
            }

            FontPtr& operator = (const ResourcePtr &p)
            {
                if (mpPtr == static_cast<Font*>(p.ptr()))
                {
                    return *this;
                }
                FontPtr temp(p);
                swap(temp);
                return *this;
            }
    };
}

#endif
